package com.joven.shelltest.utils.ruleExcute;

import com.joven.shelltest.common.constant.CommonCons;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @Author wzj
 * @Date 2023-11-22 09:27
 **/
@Component
public class RuleFactory implements InitializingBean {

    private Map<Integer, List<BaseRule>> hashMap;

    @Autowired(required = false)
    private List<BaseRule> allRuleList;

    private RuleFactory and(List<String> ruleNameList) {
        hashMap.clear();
        List<BaseRule> ruleList = new ArrayList<>();
        for (String ruleName : ruleNameList) {
            Optional<BaseRule> baseRule = allRuleList.stream().filter(baseRule1 -> ruleName.equals(baseRule1.getRuleName())).findFirst();
            baseRule.ifPresent(ruleList::add);
        }
        hashMap.put(CommonCons.RULE_AND, ruleList);
        return this;
    }

    private RuleFactory or(List<String> ruleNameList) {
        hashMap.clear();
        List<BaseRule> ruleList = new ArrayList<>();
        for (String ruleName : ruleNameList) {
            Optional<BaseRule> baseRule = allRuleList.stream().filter(baseRule1 -> ruleName.equals(baseRule1.getRuleName())).findFirst();
            baseRule.ifPresent(ruleList::add);
        }
        hashMap.put(CommonCons.RULE_OR, ruleList);
        return this;
    }

    public boolean execute(int type, RuleDto dto, List<String> ruleNameList) {
        switch (type) {
            case CommonCons.RULE_AND:
                return and(ruleNameList).execute(dto);
            case CommonCons.RULE_OR:
                return or(ruleNameList).execute(dto);
            default:
                return false;
        }
    }


    private boolean execute(RuleDto dto) {
        for (Map.Entry<Integer, List<BaseRule>> item : hashMap.entrySet()) {
            List<BaseRule> ruleList = item.getValue();
            switch (item.getKey()) {
                case CommonCons.RULE_AND:
                    // 如果是 and 关系，同步执行
                    System.out.println("execute key = " + CommonCons.RULE_AND);
                    if (!and(dto, ruleList)) {
                        return false;
                    }
                    break;
                case CommonCons.RULE_OR:
                    // 如果是 or 关系，并行执行
                    System.out.println("execute key = " + CommonCons.RULE_OR);
                    if (!or(dto, ruleList)) {
                        return false;
                    }
                    break;
                default:
                    break;
            }
        }
        return true;
    }

    private boolean and(RuleDto dto, List<BaseRule> ruleList) {
        for (BaseRule rule : ruleList) {
            boolean execute = rule.execute(dto);
            if (!execute) {
                // and 关系匹配失败一次，返回 false
                return false;
            }
        }
        // and 关系全部匹配成功，返回 true
        return true;
    }

    private boolean or(RuleDto dto, List<BaseRule> ruleList) {
        for (BaseRule rule : ruleList) {
            boolean execute = rule.execute(dto);
            if (execute) {
                // or 关系匹配到一个就返回 true
                return true;
            }
        }
        // or 关系一个都匹配不到就返回 false
        return false;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        hashMap = new HashMap<>(16);
    }
}
